package com.example.autumn.aop;

import com.example.autumn.context.*;
import com.example.autumn.exception.AopConfigException;

import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;

/**
 * @author liuzhiyong
 * @date 2023/10/27
 * description:
 */
public abstract class AnnotationProxyBeanPostProcessor<A extends Annotation> implements BeanPostProcessor {

    /**
     * 存储原对象
     */
    Map<String, Object> originBeans = new HashMap<>();

    /**
     * 当前抽象类的子类的拦截注解的泛型
     */
    Class<A> annotationClass;

    /**
     * 构造函数
     * 这个构造函数, 会在子类的后置处理器实例化的时候, 被子类调用
     * 从而为annotationClass赋值, 获取子类对象指定的注解的泛型
     *
     * @author liuzhiyong
     * @date 2023/10/30
     */
    public AnnotationProxyBeanPostProcessor() {
        this.annotationClass = getParameterizedType();
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) {
        Class<?> beanClass = bean.getClass();
        // 获取当前Bean的指定注解
        A anno = beanClass.getAnnotation(annotationClass);
        // 判断是都有需要生成代理的注解, 有的话需要生成代理
        if (anno != null) {
            String handlerName;
            try {
                // 反射执行注解中定义的value()函数, 获取指定的处理器名称
                handlerName = (String) anno.annotationType().getMethod("value").invoke(anno);
            } catch (ReflectiveOperationException e) {
                throw new AopConfigException(String.format("@%s must have value() returned String type.", this.annotationClass.getSimpleName()), e);
            }
            Object proxy = createProxy(beanClass, bean, handlerName);
            originBeans.put(beanName, bean);
            return proxy;
        } else {
            return bean;
        }
    }

    /**
     * 获取原来的Bean
     * 如果Bean没有被代理的话, 就直接返回入参, 被代理的话就返回原对象
     *
     * @param bean bean
     * @param beanName bean的名称
     * @return {@link Object }
     * @author liuzhiyong
     * @date 2023/10/30
     */
    @Override
    public Object postProcessOnSetProperty(Object bean, String beanName) {
        Object origin = this.originBeans.get(beanName);
        return origin != null ? origin : bean;
    }

    /**
     * 创建代理对象
     *
     * @param beanClass 当前Bean的Class对象
     * @param bean  当前Bean对象
     * @param handlerName 处理器的名称
     * @return {@link Object }
     * @author liuzhiyong
     * @date 2023/10/30
     */
    Object createProxy(Class<?> beanClass, Object bean, String handlerName) {
        // 获取上下文
        ConfigurableApplicationContext ctx = (ConfigurableApplicationContext) ApplicationContextUtils.getRequiredApplicationContext();
        // 获取处理器的Bean实例
        BeanDefinition def = ctx.findBeanDefinition(handlerName);
        if (def == null) {
            throw new AopConfigException(String.format("@%s proxy handler '%s' not found.", this.annotationClass.getSimpleName(), handlerName));
        }
        Object handlerBean = def.getInstance();
        // 获取Bean为null ==> 创建一个Bean
        if (handlerBean == null) {
            handlerBean = ctx.createBeanAsEarlySingleton(def);
        }
        // 如果是InvocationHandler类型, 创建代理对象
        if (handlerBean instanceof InvocationHandler handler) {
            return ProxyResolver.getInstance().createProxy(bean, handler);
        } else {
            throw new AopConfigException(String.format("@%s proxy handler '%s' is not type of %s.", this.annotationClass.getSimpleName(), handlerName,
                    InvocationHandler.class.getName()));
        }
    }


    /**
     * 获取枚举泛型A的Class对象
     * 此类是抽象类, 运行的时候, 执行的时候, 获取的是运行的子类的定义的泛型的Class对象
     *
     * @return {@link Class<A> }
     * @author liuzhiyong
     * @date 2023/10/30
     */
    @SuppressWarnings("unchecked")
    private Class<A> getParameterizedType() {
        // getClass获取的是正在执行的子类的Class对象, getGenericSuperclass() 获取父类的类型
        // 例如 public class AroundProxyBeanPostProcessor extends AnnotationProxyBeanPostProcessor<Around> {} 获取是 AnnotationProxyBeanPostProcessor 类型
        Type type = getClass().getGenericSuperclass();
        if (!(type  instanceof ParameterizedType)) {
            throw new IllegalArgumentException("Class " + getClass().getName() + " does not have parameterized type.");
        }
        ParameterizedType pt = (ParameterizedType) type;
        // 获取父类的泛型集合, 目的是获取注解
        Type[] types = pt.getActualTypeArguments();
        // 只允许一个泛型
        if (types.length != 1) {
            throw new IllegalArgumentException("Class " + getClass().getName() + " has more than 1 parameterized types.");
        }
        // 获取泛型中指定注解的Class对象
        Type r = types[0];
        if (!(r instanceof Class<?>)) {
            throw new IllegalArgumentException("Class " + getClass().getName() + " does not have parameterized type of class.");
        }
        return (Class<A>) r;
    }

}
